package br.com.base.business.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.Date;
import java.util.List;

import org.springframework.transaction.annotation.Transactional;

import br.com.base.business.Business;
import br.com.base.model.UsuarioBase;
import br.com.base.model.impl.Entidade;
import br.com.base.persistencia.DAO.IGenericDAO;
import br.com.base.persistencia.filter.IFiltro;

/**
 * 
 * @author Milton Domingues
 *
 * @param <ENTIDADE>
 * @param <ID>
 * @param <FILTRO>
 * @param <REPOSITORIO>
 */
public abstract class BusinessImpl<ENTIDADE extends Entidade<ID>, ID extends Serializable, FILTRO extends IFiltro, REPOSITORIO extends IGenericDAO<ENTIDADE, ID, FILTRO>> implements Business<ENTIDADE, ID, FILTRO, REPOSITORIO> {

	private Class<ENTIDADE> classEntidade;

	public BusinessImpl() {

	}

	public void adicionarParametroFiltro(FILTRO filtro){

	}

	@Override
	@Transactional(readOnly = true)
	public ENTIDADE buscar(ID id) {
		return this.getRepositorioDAO().buscar(id);
	}

	@Override
	public ENTIDADE buscarLoadLazy(ID id, String ...params){
		return buscar(id);
	}

	@Override
	@Transactional(readOnly = true)
	public List<ENTIDADE> consultar(FILTRO filtro) {
		adicionarParametroFiltro(filtro);
		return this.getRepositorioDAO().consultar(filtro);
	}

	@Override
	@Transactional(readOnly = true)
	public int consultarCount(FILTRO filtro) {
		adicionarParametroFiltro(filtro);
		return this.getRepositorioDAO().consultarCount(filtro).intValue();
	}

	@Override
	@Transactional
	public void editar(ENTIDADE vo, UsuarioBase usuario) {
		this.tratarDadosEntidade(vo);
		this.validarAlteracao(vo);
		this.validarUnicidade(vo);
		vo.setDataAlteracao(new Date(System.currentTimeMillis()));
		vo.setUsuarioAlteracao(usuario);
		this.resolverPerDependencias(vo, usuario);
		this.getRepositorioDAO().merge(vo);
		this.resolverPosDependencias(vo, usuario);
	}

	@Override
	@Transactional
	public void excluir(ENTIDADE vo) {
		this.validarExclusao(vo);
		vo = this.getRepositorioDAO().merge(vo);
		this.resolverPreExcluir(vo);
		this.getRepositorioDAO().excluir(vo);
	}

	@Override
	@SuppressWarnings("unchecked")
	public Class<ENTIDADE> getClassEntidade() {
		if(this.classEntidade == null){
			this.classEntidade = (Class<ENTIDADE>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		}
		return this.classEntidade;
	}

	@Override
	public abstract REPOSITORIO getRepositorioDAO();

	@Override
	@Transactional
	public void inserir(ENTIDADE vo, UsuarioBase usuario) {
		this.tratarDadosEntidade(vo);
		this.validarInclusao(vo);
		this.validarUnicidade(vo);
		vo.setDataAlteracao(new Date(System.currentTimeMillis()));
		vo.setDataInclusao(new Date(System.currentTimeMillis()));
		vo.setUsuarioInclusao(usuario);
		vo.setUsuarioAlteracao(usuario);
		this.resolverPerDependencias(vo, usuario);
		this.getRepositorioDAO().inserir(vo);
		this.resolverPosDependencias(vo, usuario);
	}

	@Override
	public abstract void resolverPerDependencias(ENTIDADE vo, UsuarioBase usuario);

	@Override
	public abstract void resolverPosDependencias(ENTIDADE vo, UsuarioBase usuario);

	@Override
	public abstract void resolverPreExcluir(ENTIDADE vo);

	@Override
	public abstract void tratarDadosEntidade(ENTIDADE vo);

	@Override
	public abstract void validarAlteracao(ENTIDADE vo);

	@Override
	public abstract void validarExclusao(ENTIDADE vo);

	@Override
	public abstract void validarInclusao(ENTIDADE vo);

	@Override
	public abstract void validarUnicidade(ENTIDADE vo);
}
